package io.xxx.mario.task.receive;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.OSSObject;
import io.xxx.mario.contact.Contact;
import io.xxx.mario.room.Room;
import io.xxx.mario.task.ReceiverType;
import io.xxx.mario.task.Task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.Map;
import java.util.Optional;

@Slf4j
@Component
public class FileReceiverSelector implements ReceiverSelector {

    @Autowired
    private OSS oss;

    @Value("${oss.bucket:example}")
    private String bucketName;

    private Optional<InputStream> getInputStream(Task task) {
        Map<String, Object> selectContent = task.getSelectContent();
        Object objectName = selectContent.get("fileUrl");
        if (objectName == null || !StringUtils.hasText(objectName.toString())) {
            log.error("文件地址不存在[taskId:{}, taskName:{}]", task.getId(), task.getName());
            return Optional.empty();
        }
        OSSObject ossObject = oss.getObject(bucketName, objectName.toString());
        return Optional.ofNullable(ossObject.getObjectContent());
    }

    private ExcelTypeEnum getExcelType(Task task) {
        Object fileType = task.getSelectContent().get("fileType");
        return fileType == null ? ExcelTypeEnum.XLSX : ExcelTypeEnum.valueOf(fileType.toString());
    }

    @Override
    public Flux<Receiver> select(Task task) {
        Optional<InputStream> inputStream = getInputStream(task);
        if (inputStream.isEmpty()) {
            return Flux.empty();
        }

        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream.get());
        Class<? extends Receiver> headClass = task.getReceiverType() == ReceiverType.ROOM ? Room.class : Contact.class;
        return Flux.create(sink -> EasyExcel.read(bufferedInputStream, headClass, new AnalysisEventListener<Receiver>() {
                    @Override
                    public void invoke(Receiver data, AnalysisContext context) {
                        sink.next(data);
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        sink.complete();
                    }
                })
                .excelType(getExcelType(task))
                .doReadAll(), FluxSink.OverflowStrategy.BUFFER);

    }
}
